package com.palm.core;

import com.alibaba.fastjson.JSON;
import com.palm.core.nami.FastjsonDecoder;
import com.palm.core.nami.FastjsonEncoder;
import com.palm.core.nami.FastjsonTypeEncoder;
import com.palm.core.util.EasyDateAnalyzer;
import com.palm.core.util.StringUtil;
import org.noear.nami.*;
import org.noear.solon.SolonApp;
import org.noear.solon.Utils;
import org.noear.solon.core.Bridge;
import org.noear.solon.core.LoadBalance;
import org.noear.solon.core.Plugin;
import org.noear.solon.core.Props;
import org.noear.solon.core.handle.Context;
import org.noear.solon.core.handle.Result;
import org.noear.solon.core.util.DateAnalyzer;
import org.sagacity.sqltoy.utils.IdUtil;

import java.io.IOException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

public class EasyCorePlugin implements Plugin {
    private static Map<String, ServiceLoadBalance> loadBalanceMap = new ConcurrentHashMap<>();

    private static void findService(String manager, String token) {
        try {
            NamiBuilder nb = Nami.builder().url(manager + "api/services");
            if (StringUtil.isNotEmpty(token)) {
                nb.headerSet("token", token);

            }
            nb.channel(NamiManager.getChannel("http"));
            Nami nami = nb.build();
            nami.url(manager+"api/services");
            ServicesResult results = nami.call(new HashMap<>(), new HashMap()).getObject(ServicesResult.class);

            List<Service> servicesList = results.getData();
            if (servicesList == null || servicesList.isEmpty()) {
                return;
            }
            for (Service s : servicesList) {
                ServiceLoadBalance sl = loadBalanceMap.get(s.getName());
                if (sl == null) {
                    sl = new ServiceLoadBalance();
                    sl.setService(s);
                    loadBalanceMap.put(s.getName(), sl);
                } else {
                    sl.setService(s);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void start(SolonApp app) {

        NamiManager.reg(FastjsonDecoder.instance);
        NamiManager.reg(FastjsonEncoder.instance);
        NamiManager.reg(FastjsonTypeEncoder.instance);

        DateAnalyzer.setGlobal(new EasyDateAnalyzer());
        Props props = app.cfg().getProp("easy");
        if (props != null&&props.getBool("enable",false)) {
            //进行初始户
            String manager = props.get("manager");
            if (StringUtil.isNotEmpty(manager)) {
                String token = props.get("token");
                //获取服务和配置
                Bridge.upstreamFactorySet(new LoadBalance.Factory() {
                    @Override
                    public synchronized LoadBalance create(String group, String service) {
                        ServiceLoadBalance lb = loadBalanceMap.get(service);
                        if (lb == null) {
                            lb = new ServiceLoadBalance();
                            loadBalanceMap.put(service, lb);
                        }
                        return lb;
                    }
                });
                NamiManager.reg(new Filter() {
                    @Override
                    public org.noear.nami.Result doFilter(Invocation inv) throws Throwable {
                        if (token != null) {
                            inv.headers.put("token", token);
                        }
                        Context ctx = Context.current();
                        if (ctx != null) {
                            String cookie = ctx.header("Cookie");
                            if (cookie != null) {
                                inv.headers.put("Cookie", cookie);
                            }
                        }
                        String traceId = ctx.header("traceId");
                        if (traceId == null) {
                            traceId = IdUtil.getUUID();
                        }
                        inv.headers.put("traceId", traceId);
                        return inv.invoke();
                    }
                });
                Utils.scheduled.scheduleWithFixedDelay(() -> findService(manager, token), 0, 1, TimeUnit.MINUTES);
            }
        }
    }

    public static class ServicesResult extends Result<List<Service>> {

    }

    public static class ServiceLoadBalance implements LoadBalance {
        private Service service;

        public void setService(Service service) {
            this.service = service;
        }

        @Override
        public String getServer() {
            return service == null ? null : service.getServer();
        }
    }

    public static class Service {
        String name;
        String title;
        List<String> urls = new ArrayList<>();

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public String getTitle() {
            return title;
        }

        public void setTitle(String title) {
            this.title = title;
        }

        public List<String> getUrls() {
            return urls;
        }

        public void setUrls(List<String> urls) {
            this.urls = urls;
        }

        private int i = 0;

        public String getServer() {
            if (urls == null || urls.size() == 0) {
                return null;
            }
            i = (i + 1) % urls.size();
            return urls.get(i);
        }
    }
}
